/** 
 * @Title:
 * @Desription:
 * @Company:CSN
 * @ClassName:Main
 * @Author:林威
 * @CreateDate:2015年4月10日
 * @UpdateUser:林威
 * @Version:0.1
 *    
 */ 
package linwei.ce;

import java.io.FileInputStream;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Arrays;

import linwei.ce.type.AccessFlags;
import linwei.ce.type.ConstantPool;
import linwei.ce.type.ConstantPoolCount;
import linwei.ce.type.MagicNumber;
import linwei.ce.type.MajorVersion;
import linwei.ce.type.MinorVersion;
import linwei.ce.type.constantpool.BaseConstant;
import linwei.ce.type.constantpool.ClassInfo;
import linwei.ce.type.constantpool.DoubleInfo;
import linwei.ce.type.constantpool.FieldRef;
import linwei.ce.type.constantpool.FloatInfo;
import linwei.ce.type.constantpool.IntegerInfo;
import linwei.ce.type.constantpool.InterfaceMethodRef;
import linwei.ce.type.constantpool.InvokeDynamic;
import linwei.ce.type.constantpool.LongInfo;
import linwei.ce.type.constantpool.MethodHandle;
import linwei.ce.type.constantpool.MethodRef;
import linwei.ce.type.constantpool.MethodType;
import linwei.ce.type.constantpool.NameAndType;
import linwei.ce.type.constantpool.StringInfo;
import linwei.ce.type.constantpool.UTF8Info;

 /** 
 * @ClassName: Main
 * @Description: 
 * @author: 林威
 * @date: 2015年4月10日
 * 
 */
public class Main {

	/**
	 * @param args
	 * @throws IOException 
	 */
	@SuppressWarnings("unused")
	public static void main(String[] args) throws IOException {
		try {
			/* 大端存储 */
			CEInputStream is = new CEInputStream(ClassLoader.getSystemResourceAsStream("StringUtils.class"));
			
			/* 魔数 */
			MagicNumber mn = new MagicNumber(is.read(4));
			
			/* 次版本 */
			MinorVersion minorVersion = new MinorVersion(is.read(2));
			
			/* 主版本号 */
			MajorVersion majorVersion = new MajorVersion(is.read(2));
			
			/* 常量池的数量 */
			ConstantPoolCount constantPoolCount = new ConstantPoolCount(is.read(2));
			int cpCount = constantPoolCount.toInt();
			
			/* 常量池 */
			ConstantPool constantPool = new ConstantPool(cpCount - 1);
			BaseConstant constantObj;
			byte[] data;
			for(int i=1; i<cpCount; i++){
				int tag = is.read();
				switch(tag){
				
				case ClassInfo.tag:
					data = new byte[3];
					data[0] = ClassInfo.tag;
					is.read(data, 1, 2);
					constantObj = new ClassInfo(data);
					break;
					
				case DoubleInfo.tag:
					data = new byte[9];
					data[0] = DoubleInfo.tag;
					is.read(data, 1, 8);
					constantObj = new DoubleInfo(data);
					break;
					
				case FieldRef.tag:
					data = new byte[5];
					data[0] = FieldRef.tag;
					is.read(data, 1, 4);
					constantObj = new FieldRef(data);
					break;
					
				case FloatInfo.tag:
					data = new byte[5];
					data[0] = FloatInfo.tag;
					is.read(data, 1, 4);
					constantObj = new FloatInfo(data);
					break;
					
				case IntegerInfo.tag:
					data = new byte[5];
					data[0] = IntegerInfo.tag;
					is.read(data, 1, 4);
					constantObj = new IntegerInfo(data);
					break;
					
				case InterfaceMethodRef.tag:
					data = new byte[5];
					data[0] = InterfaceMethodRef.tag;
					is.read(data, 1, 4);
					constantObj = new InterfaceMethodRef(data);
					break;
					
				case InvokeDynamic.tag:
					data = new byte[4];
					data[0] = InvokeDynamic.tag;
					is.read(data, 1, 3);
					constantObj = new InvokeDynamic(data);
					break;
					
				case LongInfo.tag:
					data = new byte[9];
					data[0] = LongInfo.tag;
					is.read(data, 1, 8);
					constantObj = new LongInfo(data);
					break;
					
				case MethodHandle.tag:
					data = new byte[4];
					data[0] = MethodHandle.tag;
					is.read(data, 1, 3);
					constantObj = new MethodHandle(data);
					break;
					
				case MethodRef.tag:
					data = new byte[5];
					data[0] = MethodRef.tag;
					is.read(data, 1, 4);
					constantObj = new MethodRef(data);
					break;
					
				case MethodType.tag:
					data = new byte[3];
					data[0] = MethodType.tag;
					is.read(data, 1, 2);
					constantObj = new MethodType(data);
					break;
					
				case NameAndType.tag:
					data = new byte[5];
					data[0] = NameAndType.tag;
					is.read(data, 1, 4);
					constantObj = new NameAndType(data);
					break;
					
				case StringInfo.tag:
					data = new byte[3];
					data[0] = StringInfo.tag;
					is.read(data, 1, 2);
					constantObj = new StringInfo(data);
					break;
					
				case UTF8Info.tag:
					data = new byte[3];
					data[0] = UTF8Info.tag;
					is.read(data, 1, 2);
					int bytesLength = Utils.toInt(data, 1, 2);
					data = Arrays.copyOf(data, bytesLength + 3);
					is.read(data, 3, bytesLength);
					constantObj = new UTF8Info(data);
					break;
					
				default:
					throw new Exception(MessageFormat.format("无法识别的常量池类型tag：", tag));
				}
				constantPool.add(constantObj);
				constantObj.setConstantPool(constantPool);
			}
			
			/* 打印常量池 */
			/*for(int i=1; i<cpCount; i++){
				BaseConstant c = constantPool.get(i);
				System.out.println( "#" + i + " " + c.getTypeDesc() + " " + c);
			}*/
			
			/* 访问标识 */
			AccessFlags flags = new AccessFlags(is.read(2));
			System.out.println("flags : " + flags);
			
			/**
			 * this class
			 * 2 bytes
			 */
			ClassInfo thisClass = (ClassInfo) constantPool.get(Utils.toInt(is.read(2)));
			System.out.println("thisClass : " + thisClass);
			
			/**
			 * super class
			 * 2 bytes
			 */
			ClassInfo superClass = (ClassInfo) constantPool.get(Utils.toInt(is.read(2)));
			System.out.println("superClass : " + superClass);
			
			/* interfaceCount, 接口数量 */
			int interfaceCount = Utils.toInt(is.read(2));
			/** 
			 * interface[interfaceCount], 接口列表
			 * 每个元素都是常量池索引，指向ClassInfo常量 
			 */
			for(int i=0; i<interfaceCount; i++){
				System.out.println("interface list:");
				System.out.println(constantPool.get(Utils.toInt(is.read(2))));
			}
			
			/* fieldCount, 属性数量  */
			int fieldCount = Utils.toInt(is.read(2));
			/** 
			 * field[fieldCount], 属性列表
			 * 包括类属性和实例属性，但不包括从父类继承过来的属性  
			 */
			for(int i=0; i<fieldCount; i++){
				
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
